package com.hup.joystick.service.joyEvent;

import com.hup.joystick.constant.DeviceKey.KeyType;
import com.hup.joystick.constant.DeviceKey.StandardKeys;
import com.hup.joystick.constant.FunctionConstant.FunctionType;
import com.hup.joystick.constant.FunctionConstant.MouseButton;
import com.hup.joystick.constant.FunctionConstant.QuickMenuFunctionType;
import com.hup.joystick.model.FunctionConfig;
import com.hup.joystick.model.FunctionConfig.FunctionItem;
import com.hup.joystick.model.QuickMenuFunction;
import com.hup.joystick.model.joystick.StandardEvent;
import com.hup.joystick.model.joystick.StandardEvent.StandardAction;
import com.hup.joystick.model.joystick.StandardKey;
import com.hup.joystick.service.QuickMenuFunctions;
import com.hup.joystick.view.main.MainWindow;
import com.hup.joystick.view.quickMenu.QuickMenu;
import com.hup.utils.commons.exception.AppExceptionHandler;
import com.hup.utils.commons.hardware.HRobotJni;
import com.hup.utils.commons.interfaces.Runners.RunAndThrowable;
import com.hup.utils.commons.start.DialogHelper;
import com.hup.utils.commons.start.SpringContext;
import com.hup.utils.commons.thread.ThreadPoolUtil;
import com.hup.utils.swing.frame.SingletonWindowHelper;
import lombok.extern.log4j.Log4j2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 快捷菜单功能类;
 * .按下时触发:[显示菜单,隐藏菜单,鼠标移动]
 * .抬起时触发:[鼠标点击(功能,程序):按下未抬起A时,可以按菜单键取消触发]
 *
 * @author hugan
 * @date 2020/11/10
 */
@Log4j2
public class QuickMenuFunctionHandler implements IJoyEventHandler, ActionListener {
    /**
     * 长按事件的判定间隔
     */
    private static final int LONG_PRESS_SPAN = 500;
    private final ThreadPoolExecutor executor = ThreadPoolUtil.fixedThreadExecutor("QMFunction-", 1, "快捷菜单功能线程");
    private final Robot robot;
    private final QuickMenu quickMenu;
    private final Timer timerLockJoy;
    /**
     * 锁定手柄,禁止所有操作
     */
    private boolean lockJoy;

    public QuickMenuFunctionHandler(Robot robot) {
        this.robot = robot;
        quickMenu = SpringContext.getBean(QuickMenu.class);
        timerLockJoy = new Timer(LONG_PRESS_SPAN, this);
        timerLockJoy.setRepeats(false);
    }

    private void setLockJoy(boolean lockJoy) {
        this.lockJoy = lockJoy;
        MainWindow mainWindow;
        if ((mainWindow = SingletonWindowHelper.getWindow(MainWindow.class)) != null) {
            //程序退出时达到此处,此时mainWindow为空
            mainWindow.onLockDevice(lockJoy);
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        log.debug("锁定设备");
        setLockJoy(true);
        if (quickMenu.isVisible()) quickMenu.dispose();
    }

    @Override
    public void releaseAllActiveFunction() {
        setLockJoy(false);
        if (!quickMenu.isVisible()) return;
        //窗口打开时也不需要因为手柄断线而关闭
        timerLockJoy.stop();
    }

    @Override
    public void handleRelease(StandardEvent e, StandardKey standardKey) {
        if (!quickMenu.isVisible()) return;
        //按钮A
        if (StandardKeys.A.key.equals(standardKey.key)) {
            log.info("");
            //隐藏窗口的逻辑在UI类中实现了
            robotClickMouse();
        }
        timerLockJoy.stop();
    }

    @Override
    public void handlePress(ArrayList<StandardAction> newPress, ArrayList<StandardAction> currentPress,
            FunctionConfig matchConfig) {
        //do nothing
    }

    /**
     * 处理[新按下事件];
     * .[释放事件]已经在两个release继承方法中处理了
     *
     * @param e 当前事件
     * @param newPress 新按下事件
     * @param matchConfig 配置
     * @return blockEvent:true-终止事件传递
     */
    @Override
    public boolean handlePressAndConsume(StandardEvent e, ArrayList<StandardAction> newPress,
            FunctionConfig matchConfig) {
        if (lockJoy) {
            if (hasShowMenuKey(e, newPress, matchConfig)) {
                log.debug("解除锁定");
                setLockJoy(false);
            } else {
                log.debug("设备已锁定");
            }
            return true;
        }
        if (!quickMenu.isVisible()) {
            //没显示窗口,判断有无[显示功能]
            if (hasShowMenuKey(e, newPress, matchConfig)) {
                QuickMenu.showFrame(null, null);//不能直接调用visible
                timerLockJoy.restart();
                return true;
            }
            return false;
        }

        //窗口显示中,不管有无本类的功能,都终止事件传递
        log.debug("窗口在展示, newPress.size={}", newPress.size());

        //匹配功能,匹配成功后直接return:阻止一个事件触发多个功能
        //隐藏窗口
        if (hasShowMenuKey(e, newPress, matchConfig)) {
            timerLockJoy.stop();
            quickMenu.dispose();
            return true;
        }

        //方向键
        for (StandardAction press : newPress) {
            if (press.standardKey.type == KeyType.ARROW) {
                //log.info("key={}", press.standardKey.key);
                quickMenu.onPressJoyArrow(press.standardKey.key);
                return true;
            }
        }
        return true;
    }

    private void robotClickMouse() {
        robot.mousePress(MouseButton.LEFT.button);
        robot.delay(100);
        robot.mouseRelease(MouseButton.LEFT.button);
    }

    private boolean hasShowMenuKey(StandardEvent e, ArrayList<StandardAction> newPress,
            FunctionConfig matchConfig) {
        for (StandardAction press : newPress) {
            FunctionItem showMenuFunction = IJoyEventHandler.matchPressBtnFunction(press, e.currentPress, matchConfig,
                    f -> f.functionType == FunctionType.QUICK_MENU && !f.lstStandardKey.isEmpty());
            if (showMenuFunction != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * 执行功能
     */
    public void exeFunction(QuickMenuFunction function) {
        executor.execute(() -> {
            log.info("function={}", function);
            if (function.type == QuickMenuFunctionType.KEYBOARD) {
                if (function.lstKeyCode.isEmpty()) return;
                robot.delay(20);
                for (Integer keyCode : function.lstKeyCode) robot.keyPress(keyCode);
                robot.delay(100);
                for (Integer keyCode : function.lstKeyCode) robot.keyRelease(keyCode);
            } else {
                RunAndThrowable action = QuickMenuFunctions.getCmdAction(function);
                if (action == null) {
                    log.warn("找不到内置功能={}", function.cmdDesc);
                    return;//正常情况,鼠标点击事件时已经过滤了
                }
                try {
                    action.run();
                } catch (Throwable e) {
                    AppExceptionHandler.handle("[" + function.cmdDesc + "]执行错误", e);
                }
            }
        });
    }

    public void runApp(String filePath) {
        try {
            log.debug("运行={}", filePath);
            HRobotJni.shellExecuteRun(filePath);
        } catch (IOException e) {
            DialogHelper.show("运行失败:", e, null);
        }
    }

}
